package uk.ac.cam.djjb2.mygame;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public final class Vector2d {
	public final double x;
	public final double y;
	
	public static final Vector2d ZERO = new Vector2d();
	
	public Vector2d() {
		this.x = 0;
		this.y = 0;
	}
	public Vector2d(double x, double y) {
		this.x = x;
		this.y = y;
	}
	
	public Vector2d add(Vector2d other) {
		return new Vector2d(this.x + other.x, this.y + other.y);
	}
	public Vector2d add(double x, double y) {
		return new Vector2d(this.x + x, this.y + y);
	}
	public Vector2d sub(Vector2i other) {
		return new Vector2d(this.x - other.x, this.y - other.y);
	}
	public Vector2d sub(double x, double y) {
		return new Vector2d(this.x - x, this.y - y);
	}
	public Vector2d negate() {
		return new Vector2d(-this.x, -this.y);
	}
	public Vector2d mul(double other) {
		return new Vector2d(this.x * other, this.y * other);
	}
	public Vector2d mul(Vector2i other) {
		return new Vector2d(this.x * other.x, this.y * other.y);
	}
	public Vector2d div(double other) {
		return new Vector2d(this.x / other, this.y / other);
	}
	public Vector2d div(Vector2d other) {
		return new Vector2d(this.x / other.x, this.y / other.y);
	}
	public double dot(Vector2d other) {
		return this.x * other.x + this.y * other.y;
	}
	public Vector2d cross() {
		return new Vector2d(-this.y, this.x);
	}
	public double lengthSq() {
		return this.x*this.x + this.y*this.y;
	}
	public double length() {
		return Math.sqrt(this.lengthSq());
	}
	public double angle() {
		return Math.atan2(y, x);
	}
	public Vector2d normalize() {
		return mul(1.0/length());
	}
	public Vector2d normalize(double length) {
		return mul(length/length());
	}
	public Vector2d rotate(double angle) {
		double ca = Math.cos(angle);
		double sa = Math.sin(angle);
		return new Vector2d(x*ca - y*sa, x*sa + y*ca);
	}
	
	@Override
	public int hashCode() {
		long ix = Double.doubleToLongBits(x);
		long iy = Double.doubleToLongBits(y);
		return (int)(ix^(ix>>>32)) + (int)(iy^(iy>>>32))*3571;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (obj instanceof Vector2i) {
			Vector2d other = (Vector2d) obj;
			if (x != other.x)
				return false;
			if (y != other.y)
				return false;
			return true;
		}
		return false;
	}
	public boolean equals(Vector2d other, double tolerance) {
		if (this == other)
			return true;
		if (other == null)
			return false;

		if (Math.abs(this.x - other.x) > tolerance)
			return false;
		if (Math.abs(this.y - other.y) > tolerance)
			return false;

		return true;
	}
	public String toString() {
		return "[Vector2d ("+x+", "+y+")]";
	}
	public Vector2i toVector2i() {
		return new Vector2i((int)x, (int)y);
	}
	
	public static Vector2d fromPolar(double angle, double length) {
		return new Vector2d(Math.cos(angle)*length, Math.sin(angle)*length);
	}
	public static void write(DataOutput output, Vector2d vec) throws IOException {
		output.writeDouble(vec.x);
		output.writeDouble(vec.y);
	}
	public static Vector2d read(DataInput input) throws IOException {
		return new Vector2d(
				input.readDouble(),
				input.readDouble()
				);
	}
}
